Skip to content

2757. 生成循环数组的值

2757. 生成循环数组的值

ts
function* cycleGenerator(
  arr: number[],
  startIndex: number
): Generator<number, void, number> {
  const len = arr.length
  let currentIndex = ((startIndex % len) + len) % len // 处理负的 startIndex

  while (true) {
    const jump = yield arr[currentIndex]

    if (typeof jump === 'number') {
      currentIndex = (((currentIndex + jump) % len) + len) % len
    }
  }
}

yield 的双向通信

yield 不只是「产出值」,它还可以接收值const jump = yield arr[currentIndex] 同时做了两件事:

  1. 产出 arr[currentIndex] 给调用方
  2. 暂停,等待调用方通过 .next(value) 传入值,赋给 jump

如果调用方调的是 .next()(无参数),jumpundefined,索引不变——下次调用继续产出同一序列的下一个元素。如果调用方传入了数字,索引按 jump 跳转。

这是 Generator 和普通迭代器的关键区别:Generator 支持双向通信

负数取模的处理

((startIndex % len) + len) % len 是 JavaScript 中处理负数取模的标准写法。JavaScript 的 % 对负数的行为是「余数」而非「模」——-1 % 5 返回 -1 而非 4。通过 ((x % n) + n) % n 确保结果始终在 [0, n-1] 范围内。

两次模运算对性能影响通常很小(len 不变),如果确实处在极热路径里,也可以先把 startIndex 预处理成正数:if (startIndex < 0) startIndex += Math.ceil(-startIndex / len) * len

无限循环

while (true) 使这个 Generator 永远不会自行终止——调用方需要自己决定何时停止(通过 breakreturn 退出 for...of)。这符合「循环数组」的语义:数组是环形的,没有终点。